package com.dp.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import java.text.SimpleDateFormat;
import com.dp.client.dto.AlmacenDTO;
import com.dp.client.dto.EstadoPaqueteDTO;
import com.dp.client.dto.PaqueteDTO;
import com.dp.client.dto.PaqueteEnvio;
import com.dp.client.dto.RutasVueloEnvio;
import com.dp.client.dto.VueloDTO;
import com.dp.client.servicios.paquete.IServiciosPaquete;
import com.dp.server.entities.Almacen;
import com.dp.server.entities.EstadoPaquete;
import com.dp.server.entities.Paquete;
import com.dp.server.entities.PlanDeVuelo;
import com.dp.server.entities.ReservaVuelo;
import com.dp.server.entities.Vuelo;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")

public class IServiciosPaqueteImpl extends RemoteServiceServlet implements IServiciosPaquete {
	static int cte = 60 * 60 * 1000;
	IServiciosIncidenciaImpl incidencia = new IServiciosIncidenciaImpl();
	MantenimientoGenerico<Paquete> mPaquete = new MantenimientoGenerico<>("Paquete");
	final private MantenimientoGenerico<Almacen> mantenimientoGenerico= new MantenimientoGenerico("Almacen");
	
	@Override
	public PaqueteDTO registrarPaquete(PaqueteDTO paqueteDTO) {
		
		Almacen aOrigen=mantenimientoGenerico.buscarID(paqueteDTO.almacenOrigen);
		Almacen aDestino=mantenimientoGenerico.buscarID(paqueteDTO.almacenDestino);
		paqueteDTO.nombAlmacenOrigen = aOrigen.getDescripcion();
		paqueteDTO.nombAlmacenDestino = aDestino.getDescripcion();
		Paquete paquete = new Paquete(paqueteDTO);
		
		// saving the data on DB
		//EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("some_name_you_choose");
		
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		EntityManager entityManager = entityManagerFactory
				.createEntityManager();
		entityManager.getTransaction().begin();
		Paquete c = entityManager.merge(paquete);
		entityManager.getTransaction().commit();
		entityManager.close();
		PaqueteDTO nuevoDTO=c.extractDTO();
		
		return nuevoDTO;
	}
	
	public boolean registrar(Paquete paquete) {
		// saving the data on DB
		//EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("some_name_you_choose");
		Almacen aOrigen=mantenimientoGenerico.buscarID(paquete.getAlmacenOrigen());
		Almacen aDestino=mantenimientoGenerico.buscarID(paquete.getAlmacenDestino());
		paquete.setNombAlmacenOrigen(aOrigen.getDescripcion());
		paquete.setNombAlmacenDestino(aDestino.getDescripcion());
		
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		EntityManager entityManager = entityManagerFactory
				.createEntityManager();
		entityManager.getTransaction().begin();
		Paquete c = entityManager.merge(paquete);
		entityManager.getTransaction().commit();
		entityManager.close();
		//PaqueteD nuevoDTO=c.extractDTO();
		
		if (paquete.getEstadoPaquete()==4){
			MantenimientoGenerico<PlanDeVuelo> pdv=new MantenimientoGenerico<>("PlanDeVuelo");
			PlanDeVuelo planDeVuelo=pdv.buscarID(paquete.getPlanDeVuelo());
			if( planDeVuelo == null ) return true;
			planDeVuelo.recoger();
			pdv.registra(planDeVuelo);
		}
		
		return true;
	}
	
	//devuelve los paquetes sin ruta
	public List<Paquete> CargaMasiva(List<Paquete> lista)
	{
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		entityManager.getTransaction().begin();
		List<Paquete> paquete = new ArrayList<Paquete>();
		for(int i=0;i<lista.size();i++)
		{
			Almacen aOrigen=mantenimientoGenerico.buscarID(lista.get(i).getAlmacenOrigen());
			Almacen aDestino=mantenimientoGenerico.buscarID(lista.get(i).getAlmacenDestino());
			lista.get(i).setNombAlmacenOrigen(aOrigen.getDescripcion());
			lista.get(i).setNombAlmacenDestino(aDestino.getDescripcion());
			Paquete c = entityManager.merge(lista.get(i));
			paquete.add(c);
			//entityManager.getTransaction().commit();
			//GeneraVuelo(c);
		}
		entityManager.getTransaction().commit();
		entityManager.close();
		List<Paquete> sinRuta = new ArrayList<Paquete>();
		for(int i=0;i<paquete.size();i++)
		{
			if(!GeneraVuelo(paquete.get(i)))
				sinRuta.add(paquete.get(i));
		}
		return sinRuta;
	}
	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	static Random random = new Random();
	
	public boolean GeneraVuelo(Paquete c)
	{
		AlmacenDTO origen=(new IServiciosAlmacenImpl()).getAlmacen(c.getAlmacenActual());
		AlmacenDTO destino=(new IServiciosAlmacenImpl()).getAlmacen(c.getAlmacenDestino());
		Date fechaR =c.getFechaRegistro();
		
		Date fechaE = c.getFechaEstimadaLlegada();
		
		PaqueteEnvio pqt = new PaqueteEnvio ( origen.getDescripcion() ,destino.getDescripcion() , fechaR , fechaE );
		IServiciosSimulacionImpl simulacion = new IServiciosSimulacionImpl();
		List < RutasVueloEnvio > rutas=simulacion.obtenerRutas(pqt);
		if (rutas.size()==0){
			c.setEstadoPaquete( 2 );
			c.reruteo();
			registrar(c);
			//aca no hubo ruta, con probabilidad 0.94 se le va a asignar una nueva ruta vacia
			if(random.nextDouble() <= 0.94){
				int[] vuelos = new int[0];
				int pos = generarPlanDeVuelo(c.getId(), vuelos);
				c.setPlanDeVuelo(pos);
				c.setReruteo(false);
				c.setEstadoPaquete(2);
				registrar(c);
				return true;
			}
			return false;
		}
		for (RutasVueloEnvio r:rutas){
			if ( simulacion.ejecutaRuta(r, pqt ) ){
				int [] vuelos=new int [r.vuelos.size()];
				for ( int x=0 ; x < r.vuelos.size() ; x++ )
				{
					vuelos[ x ] = r.vuelos.get(x).idVuelo;
				}
					int pos = generarPlanDeVuelo(c.getId(), vuelos);
					c.setPlanDeVuelo(pos);
					c.setReruteo(false);
					c.setEstadoPaquete(2);
					registrar(c);
					//new IServiciosEnviarCorreo().CambioRuta(c.getClienteRemintente(), c.getClienteDestinatario(), c);
					return true;
			}
		}
		
		return false;
	}
	
	@Override
	public List<PaqueteDTO> listPaquetesCliente(int clienteId, Date fin,
			Date inicio, String codigoPqt) {
		
		String sInicio = "0000-00-00 00:00:00" , sFin = "9999-12-12 00:00:00";
		if( inicio != null ) inicio.setTime(( inicio.getTime() / cte ) * cte );
		if( fin != null )    fin.setTime(( fin.getTime() / cte ) * cte );
		if( inicio != null ) sInicio = format.format( inicio );
		if( fin != null ) sFin = format.format( fin );
		
		String fecha = "and fechaEstimadaLlegada between '" + sInicio + "' and '" + sFin  + "' " ;
		List<PaqueteDTO> todosPaquetes;
		if (codigoPqt.compareTo("")!=0){
			fecha+=" and codigo like '%"+codigoPqt+"%' ";
		}
		 List <Paquete> paquetes=mPaquete.listExtendido(fecha);
		 todosPaquetes = new ArrayList<>();
		 for (Paquete p: paquetes){
			 todosPaquetes.add(p.extractDTO());
		 }

		ArrayList<PaqueteDTO> result = new ArrayList<>();
		
		for (PaqueteDTO p : todosPaquetes) {
			String desc="";
			
			if ((clienteId > 0 && !(clienteId == p.getClienteDestinatario() || clienteId == p
					.getClienteRemitente())))
				continue;
			//if (codigoPqt > 0 && p.getId() != codigoPqt)
				//continue;
			
			if(p.getEstadoPaquete()<3 || (p.getEstadoPaquete()==3 && p.getVueloActual()==0)){
				//System.out.println("almacen");
				AlmacenDTO a=( new IServiciosAlmacenImpl().getAlmacen( p.getAlmacenActual() ) );
				desc=a.getDescripcion();
				
			}
			else if (p.getEstadoPaquete()==3){
				//System.out.println("VUELO");
				VueloDTO v= (new IServiciosConexionImpl().buscarVuelo(p.vueloActual));
				desc="En vuelo de " +v.almacenOrigen.getDescripcion()+" a "+v.almacenDestino.getDescripcion();
			}
			else{
				//System.out.println("RE");
				desc="Recogido";
			}
			p.setUbicacion(desc);
			result.add(p);
		}
		return result;
	}

	@Override
	public List<PaqueteDTO> listPaquetes() {
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		//EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("some_name_you_choose");
		EntityManager entityManager = entityManagerFactory
				.createEntityManager();
		List<Paquete> lista = entityManager.createQuery("from Paquete").getResultList();
		entityManager.close();
		ArrayList<PaqueteDTO> result = new ArrayList<PaqueteDTO>();
		for (Paquete c : lista) {
			result.add(c.extractDTO());
		}
		return result;
	}

	@Override
	public List<PaqueteDTO> listPaquetesQuery(int idAlmacen, String estado,
			String codigo, int idVuelo) {
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		//EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("some_name_you_choose");
		EntityManager entityManager = entityManagerFactory
				.createEntityManager();
		String query = "from Paquete where  almacenActual=" + idAlmacen /*+ " and estadoPaquete <> 4"*/;
		if (Integer.parseInt(estado) > 0)
			query += "and estadoPaquete=" + estado + " ";
		else {
			int estadoVuelo = (new IServiciosEstadoPaqueteImpl())
					.getId("vuelo");
			query += "and estadoPaquete<>" + estadoVuelo + " ";
		}
		if (codigo.length() > 0)
			query += "and codigo like '%" + codigo + "%' ";
		// query+="and id ="+codigo+" ";
		
		
		List<Paquete> lista = entityManager.createQuery(query).getResultList();
		entityManager.close();
		ArrayList<PaqueteDTO> result = new ArrayList<PaqueteDTO>();
		MantenimientoGenerico<ReservaVuelo> mVuelo=new MantenimientoGenerico<>("ReservaVuelo");
		for (Paquete c : lista) {
			if (idVuelo>0){
				boolean v=mVuelo.existeObjeto(" and idPaquete = "+c.getId()+" and id = "+idVuelo+" ");
				if (!v) continue;
			}
			result.add(c.extractDTO());
		}
		return result;

	}

	@Override
	public List<PaqueteDTO> listPaquetesAlmacen(int idAlmacen) {
		List<PaqueteDTO> todosPaquetes = listPaquetes();
		ArrayList<PaqueteDTO> result = new ArrayList<>();

		List<EstadoPaqueteDTO> estados = (new IServiciosEstadoPaqueteImpl())
				.listEstadoPaquete();
		int idEstado = 0;

		for (EstadoPaqueteDTO e : estados) {
			if (e.getDescripcion().compareTo("vuelo") == 0) {
				idEstado = e.getId();
				break;
			}
		}
		for (PaqueteDTO p : todosPaquetes) {
			if (p.almacenActual == idAlmacen && p.estadoPaquete!=3)/*diferente de 4 que es recogido y 3 que es en vuelo*/
				{
					result.add(p);
				}
		}
		return result;
	}

	@Override
	public boolean eliminarPaquete(int paqueteId) {
		String msg="Se ha eliminado el paquete con id "+paqueteId+". ";
		incidencia.Registrar(msg, "paquete", paqueteId);
		//EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("some_name_you_choose");
		EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		entityManager.getTransaction().begin();
		entityManager
				.createQuery("delete from paquete where id = " + paqueteId)
				.executeUpdate();
		entityManager.getTransaction().commit();
		entityManager.close();
		return true;
	}
	
	@Override
	public Integer generarPlanDeVuelo(int idPaquete, int[] idVuelo) {
		
		Paquete paq = mPaquete.buscarID(idPaquete);
		PlanDeVuelo plan = PlanDeVuelo.createPlan(paq, idVuelo);
		if (plan == null)	return -1;
		return plan.getId();
	}

	@Override
	public List<VueloDTO> listPaquetePorVuelo(int id) {
		
		return null;
	}

	@Override
	public boolean MovimientoPaqueteAlmacen(PaqueteDTO paquete) {
		
		if (paquete.estadoPaquete == 4)
			return false;/*el paquete fue recogido*/
		paquete.setEstadoPaquete(paquete.estadoPaquete+1);
		if (paquete.almacenActual==paquete.almacenDestino && paquete.estadoPaquete==1){
			paquete.setFechaRealLlegada(new Date());
		}
	registrarPaquete(paquete);
		return true;
	}
	
	public Paquete obtenerPaquete(String codigo)
	{
		try
		{
			EntityManagerFactory entityManagerFactory=MantenimientoGenerico.entityManagerFactory;
			EntityManager entityManager = entityManagerFactory.createEntityManager();
			Paquete paquete = (Paquete)entityManager.createQuery("from Paquete where codigo = '"+codigo+"' ").getResultList().get(0);
			entityManager.close();
			return paquete;
		}
		catch(Exception e)
		{
			return null;
		}		
	}
}
